
trait Pushable {
    fn push_once(self, c: char); //DoOnce Semantic
    fn push_more(self, c: char) -> Self; //DoManyTimes Semantic
}

#[cfg(test)]
mod test{
    use super::*;

    #[test]
    // [1]. Struct contains  mutable ref which wrapped by RefCell 
    // [2]. impl Trait with fn(self, ...); 
    // [3]. calling an object with internal changable operation.
    fn use_refcell() {
        use std::cell::RefCell;
        struct Serializer<'a> {
            output: RefCell<&'a mut String>, //NOTE: [1] contains an mutable ref  
        }


        impl<'a> Serializer<'a> {
            fn new(s: &'a mut String) -> Self{
                Self {
                    output: RefCell::new(s),
                }
            }
        }

        // this is the target use
        impl<'a> Pushable for Serializer<'a>{
            fn push_once(self, c: char) { //NOTE: [2] self is moved parameter
                self.output.borrow_mut().push(c);
            }
            fn push_more(self, c: char) -> Self{
                self.output.borrow_mut().push(c);
                self
            }
        }

        let mut result = String::new();
        let ser = Serializer::new(&mut result); // [3]
        ser.push_more('h').push_once('c');
    }

    //IMMutable struct (&mut ref) 
    //  2. Use impl for &'a mut T 
    #[test]
    // [1]. Struct contains  internal object 's with no-mut decorator
    // [2]. Dest Trait with fn(self, ...) -> with change internal state;
    // [3]. impl Trait for mutable ref [ &mut T, &'a mut T]
    // [4]. calling an object with internal changable operation.
    fn imm_contains_mut_high_performance(){
        struct Serializer {  
            output: String ,//NOTE: [1]
        }

        impl Serializer {
            fn new() -> Self {
                Self {
                    output: String::new()
                }
            }
        }

        impl<'a> Pushable for &'a mut Serializer {  //NOTE: [3]  impl for an mutable refer
            fn push_once(self, c: char){    //NOTE: [2] , change the output: String
                self.output.push(c);
            }
            fn push_more(self, c: char) -> Self{ //NOTE: [2] change the output: String
                self.output.push(c);
                self
            }
        }

        let mut ser = Serializer::new();
        (&mut ser).push_more('h'); //NOTE: [4] move the &'a mut Serial ref
        (&mut ser).push_more('h'); //NOTE: [4] move the &'a mut Serial ref

        (&mut ser).push_once('c');
        println!("{}", ser.output);
    }



}

